#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <fcntl.h>

#define LEFT "["
#define RIGHT "]"
#define LABLE "#"
#define DELIM " \t"
#define LINE_SIZE 1024
#define ARGC_SIZE 32
#define EXIT_CODE 44

#define NONE -1
#define IN_RDIR 0
#define OUT_RDIR 1
#define APPEND_RDIR 2

int quit = 0;
int lastcode=0;
extern char **environ;
char commandline[LINE_SIZE];
char *argv[ARGC_SIZE];
char pwd[LINE_SIZE];
char *rdirfilename = NULL;
int rdir = NONE;


//自定义环境变量表
char myenv[LINE_SIZE];
//自定义本地变量表

const char *getusername()
{
  return getenv("USER");
}

const char *gethostname()
{
  return getenv("HOSTNAME");
}

void getpwd()
{
  getcwd(pwd,sizeof(pwd));
  //return getenv("PWD");
}

void check_redir(char *cmd)
{
  char *pos = cmd;
  while(*pos)
  {
    if(*pos == '>')
    {
      if(*(pos+1) == '>')
      {
        *pos++ = '\0';
        *pos++ = '\0';
        while(isspace(*pos))  pos++;
        rdirfilename = pos;
        rdir = APPEND_RDIR;
        break;
      }
      else
      {
        *pos = '\0';
        pos++;
        while(isspace(*pos)) pos++;
        rdirfilename = pos;
        rdir = OUT_RDIR;
        break;
      }
      
    }
    else if(*pos == '<')
    {
      *pos = '\0';
      pos++;
      while(isspace(*pos))  pos++;
      rdirfilename = pos;
      rdir = OUT_RDIR;
      break;
    }
    else 
    {
      //do nothing
    }
    pos++;
  }

}

void Interact(char *cline,int size)
{
  getpwd();
  printf(LEFT"%s@%s %s" RIGHT "" LABLE " ",getusername(),gethostname(),pwd);
  //scanf("%s",commandline);
  char *s = fgets(cline,size,stdin);
  assert(s != NULL);
  (void) s;

  //"abcd\n\0"
  cline[strlen(cline)-1] = '\0';
  
  //ls -a -l > myfile.txt
  check_redir(cline);
}

int splitstring(char cline[],char *_argv[])
{
  int i=0;
  _argv[i++]=strtok(cline,DELIM);
  while(_argv[i++] = strtok(NULL,DELIM)); //故意写的=
  return i-1;
}

void NormalExcute(char *_argv[])
{
    pid_t id = fork();
    if(id < 0){
      perror("fork error\n");
      return;
    }
    else if(id == 0){
      int fd = 0;

      if(rdir == IN_RDIR)
      {
        fd = open(rdirfilename,O_RDONLY,0666);
        dup2(fd,0);
      }
      else if(rdir == OUT_RDIR)
      {
        fd = open(rdirfilename,O_CREAT|O_WRONLY|O_TRUNC,0666);
        dup2(fd,1);
      }
      else if(rdir == APPEND_RDIR)
      {
        fd = open(rdirfilename,O_CREAT|O_WRONLY|O_APPEND,0666);
        dup2(fd,1);
      }
      //child
      //execvpe(_argv[0],_argv,environ);
      execvp(_argv[0],_argv);
      exit(EXIT_CODE);
    }
    else{
      //father
      int status = 0;
      pid_t rid = waitpid(id,&status,0);
      if(rid == id)
      {
        lastcode=WEXITSTATUS(status);
      }
    }
  
}

int buildCommand(char *_argv[],int _argc)
{
    if(_argc == 2 && strcmp(_argv[0],"cd")==0)
    {
      chdir(argv[1]);
      getpwd();
      sprintf(getenv("PWD"),"%s",pwd);
      return 1;
    }
    else if(strcmp(_argv[0],"export")==0)
    {
      strcpy(myenv,_argv[1]);
      putenv(myenv);
      return 1;
    }
    else if(strcmp(_argv[0],"echo")==0)
    {
      if(strcmp(_argv[1],"$?")==0)
      {
        printf("%d\n",lastcode);
        lastcode=0;
      }
      else if(*_argv[1] == '$')
      {
        char *val = getenv(_argv[1]+1);
        if(val) printf("%s\n",getenv(_argv[1]+1));
      }
      else 
      {
        printf("%s\n",_argv[1]);
      }
      return 1;
    }

    if(strcmp(_argv[0],"ls")==0)
    {
      _argv[_argc++] = "--color";
      _argv[_argc] = NULL;
    }
    return 0;
}

int main()
{
  while(!quit){
    rdirfilename = NULL;
    rdir = NONE;
    //2.交互问题，获取命令行
    Interact(commandline,sizeof(commandline));
    
    //3.字串分割问题，解析命令行
    int argc = splitstring(commandline,argv);
    if(argc == 0) continue;
    
    //4.指令的判断
    //debug
    //for(int i=0;argv[i];i++)  printf("[%d]: %s\n",i,argv[i]);
    //内建命令,本质上是shell内部的一个函数
    int n=buildCommand(argv,argc);

    //5.普通命令的执行
    if(n == 0) NormalExcute(argv);
  }

  return 0;
}
